/******************************************************************************
	Cobalt - utility libraries for building XNA games
	Copyright (C) 2008 Philip Djonov

	This program is free software; you can redistribute it and/or modify it
	under the terms of the GNU General Public License as published by the Free
	Software Foundation; either version 2 of the License, or (at your option)
	any later version.

	This program is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
	for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the
	
		Free Software Foundation, Inc.
		51 Franklin Street, Fifth Floor
		Boston, MA  02110-1301, USA.
******************************************************************************/

using System;
using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;

namespace Cobalt.Content.Pipeline.Quake.Bsp
{
	[ContentTypeWriter]
	public class CompiledBspWriter : ContentTypeWriter<CompiledBsp>
	{
		protected override void Write( ContentWriter output, CompiledBsp value )
		{
			output.Write( value.Entities.Count );
			foreach( Entity ent in value.Entities )
			{
				output.Write( EntityTypeMap.GetTypeId( ent ) );
				output.Write( ent.Target != null ? ent.Target.Index : -1 );
				ent.Write( output );
			}

			output.Write( value.Lightmaps.Count );
			foreach( Texture2DContent lmap in value.Lightmaps )
			{
				output.WriteObject( lmap );
			}

			output.Write( value.Materials.Count );
			foreach( MaterialContent mat in value.Materials )
			{
				output.WriteObject( mat );

				int lightmapIndex = -1;

				Graphics.CobaltMaterialContent cobMat = mat as Graphics.CobaltMaterialContent;
				if( cobMat != null )
					lightmapIndex = value.Lightmaps.IndexOf(
						cobMat.PipelineTags.GetValue<Texture2DContent>( "Lightmap", null ) );
				
				output.Write( lightmapIndex );
			}

			output.Write( value.Buffers.Count );
			foreach( GeometryBuffer buf in value.Buffers )
			{
				output.WriteObject( buf.VertexDeclaration );
				output.WriteObject( buf.Vertices );
				output.WriteObject( buf.Indices );
			}

			output.Write( value.Surfaces.Count );
			foreach( Surface surf in value.Surfaces )
			{
				output.Write( surf.Buffer.Index );
				output.Write( value.Materials.IndexOf( surf.Material ) );
				output.Write( surf.FirstVertex );
				output.Write( surf.VertexCount );
				output.Write( surf.FirstIndex );
				output.Write( surf.IndexCount / 3 );
			}

			output.Write( value.Brushes.Count );
			foreach( Brush brush in value.Brushes )
			{
				output.Write( brush.ContentFlags );
				output.Write( brush.Sides.Count );
				foreach( BrushSide side in brush.Sides )
				{
					output.WriteRawObject( side.Plane );
					output.Write( side.SurfaceFlags );
				}
			}

			output.Write( value.LeafNodes.Count );
			foreach( BspLeafNode leaf in value.LeafNodes )
			{
				output.WriteRawObject( leaf.Bounds );
				output.Write( leaf.PvsCluster != null ? leaf.PvsCluster.ClusterNum : -1 );

				output.Write( leaf.Brushes.Count );
				foreach( Brush b in leaf.Brushes )
					output.Write( b.Index );

				output.Write( leaf.Surfaces.Count );
				foreach( Surface s in leaf.Surfaces )
					output.Write( s.Index );
			}

			output.Write( value.PartitionNodes.Count );
			foreach( BspPartitionNode part in value.PartitionNodes )
			{
				output.WriteRawObject( part.Bounds );

				output.WriteRawObject( part.Plane );

				if( part.Child0 == null )
					output.Write( (int)0 );
				else
					output.Write( part.Child0 is BspPartitionNode ? part.Child0.Index + 1 : -(part.Child0.Index + 1) );

				if( part.Child1 == null )
					output.Write( (int)0 );
				else
					output.Write( part.Child1 is BspPartitionNode ? part.Child1.Index + 1 : -(part.Child1.Index + 1) );

				output.Write( part.Surfaces.Count );
				foreach( Surface s in part.Surfaces )
					output.Write( s.Index );
			}

			if( value.PvsData != null )
			{
				output.Write( value.PvsData.Clusters.Count );
				output.Write( value.PvsData.PvsConnectivityBits.Length );
				for( int i = 0; i < value.PvsData.PvsConnectivityBits.Length; i++ )
					output.Write( value.PvsData.PvsConnectivityBits[i] );
			}
			else
			{
				output.Write( (int)0 );
				output.Write( (int)0 );
			}
		}

		public override string GetRuntimeType( TargetPlatform targetPlatform )
		{
			return Helpers.GetCobaltFrameworkTypeString( "Bsp.BspData" );
		}

		public override string GetRuntimeReader( TargetPlatform targetPlatform )
		{
			return Helpers.GetCobaltFrameworkTypeString( "Bsp.Content.BspReader" );
		}
	}
}
